/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "http2_napi.h"
#include "http2_common.h"
#include "http2_constant.h"
#include "napi/http2_constant.h"
#include "ohos_log.h"
#include <cstddef>
#include <thread>

RequestCallback* HandleRequestCallback(int type, void *data, int len, int rpcType, std::string reqId)
{
    void *swapData = nullptr;
    char *responseHeaders = nullptr;
    uint8_t *responseDataTrunck = nullptr;
    int errorCode = 0;
    if (type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE || type == HTTP_STREAM_CALLBACK_TYPE_ERROR ||
        type == HTTP_CALLBACK_TYPE_CLOSE && data) {
        int allocLen = strlen((char *)data) + 1;
        if (len >= 0 && len <= MAX_ALLOC_SIZE) {
            responseHeaders = (char *)malloc(allocLen);
            std::copy((uint8_t *)data, (uint8_t *)data + allocLen, responseHeaders);
            swapData = responseHeaders;
        }
    }
    if (type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE_DATA_TRUNCK) {
        if (len >= 0 && len <= MAX_ALLOC_SIZE && data) {
            responseDataTrunck = (uint8_t *)malloc(len + 1);
            std::copy((uint8_t *)data, (uint8_t *)data + len + 1, responseDataTrunck);
            swapData = responseDataTrunck;
        }
    }
    auto callbackManagerIt = g_callbackManagerMap.Find(reqId);
    if (callbackManagerIt == g_callbackManagerMap.End()) {
        LOGE("HandleRequestCallback callbackManagerMap not found reqId %s", reqId.c_str());
        return nullptr;
    }
    auto envManagerIt = g_envManagerMap.Find(reqId);
    if (envManagerIt == g_envManagerMap.End()) {
        LOGE("HandleRequestCallback envManagerMap not found reqId %s", reqId.c_str());
        return nullptr;
    }
    auto env = envManagerIt->second;
    auto callbackRef = callbackManagerIt->second;
    LOGE("HandleRequestCallback %p type %d reqId %s ", callbackRef, type, reqId.c_str());
    RequestCallback *requestCallback = new RequestCallback{.env = env,
                                                           .callbackRef = callbackRef,
                                                           .type = type,
                                                           .errorCode = errorCode,
                                                           .reqId = reqId,
                                                           .data = swapData,
                                                           .rpcType = rpcType,
                                                           .dataLen = len};
    return requestCallback;
}

void HandleResponseData(RequestCallback *requestCallback, napi_value* dataNV)
{
    if (requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE ||
        requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_ERROR ||
        requestCallback->type == HTTP_CALLBACK_TYPE_CLOSE) {
        napi_create_string_utf8(requestCallback->env, (char *)requestCallback->data, NAPI_AUTO_LENGTH, dataNV);
    }
    if (requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE_DATA_TRUNCK) {
        if (requestCallback->dataLen > NUM_5) {
            uint8_t *tempData = (uint8_t *)requestCallback->data;
            size_t startIndex = INDEX_5;
            size_t copyLength =  requestCallback->dataLen - INDEX_5;
            if (copyLength > MAX_ALLOC_SIZE || copyLength < 0) {
                return;
            }
            uint8_t *clippedData = (uint8_t *)malloc(copyLength);
            std::copy(tempData + startIndex, tempData + startIndex + copyLength, clippedData);
            CreateArrayBuffer(requestCallback->env, clippedData, copyLength, dataNV);
            if (clippedData) {
                free(clippedData);
                clippedData = nullptr;
            }
        } else {
            CreateArrayBuffer(requestCallback->env, requestCallback->data, requestCallback->dataLen, dataNV);
        }
    }
}

bool ReadWriteBuffer(struct pollfd* pollfds, int npollfds, Connection& connection,
    RequestTask* requestTask, bool& streamError)
{
    int nfds = poll(pollfds, npollfds, NUM_30000);
    if (nfds == -1) {
        LOGE("poll %s", strerror(errno));
    }
    if (pollfds[0].revents & (POLLIN | POLLOUT)) {
        auto handleIoResult = HandleIo(&connection, requestTask->reqId);
        if (handleIoResult.code < 0) {
            LOGE("HandleIo error reqId %s", requestTask->reqId.c_str());
            if (handleIoResult.isRecv) {
                streamError = true;
            }
            return true;
        }
    }
    if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
        LOGE("nghttp2_session_want_read error reqId %s", requestTask->reqId.c_str());
        streamError = true;
        return true;
    }
    CtlPoll(pollfds, connection.session, connection.wantIo);
    return false;
}


bool ReadDataTask(const RequestTask *requestTask, const Connection &connection)
{
    if (nghttp2_session_want_read(connection.session)) {
        if (connection.session) {
            nghttp2_session_recv(connection.session);
        }
        if (IsDestroyed(requestTask->reqId)) {
            LOGE("ReadDataThread stop");
            return true;
        }
    }
    return false;
}

void ReadDataThread(RequestTask *requestTask, Connection connection)
{
    auto recvTask = [](const RequestTask *requestTask, const Connection &connection) {
        usleep(NUM_1000 * NUM_100);
        while (!g_streamCloseManagerMap[requestTask->reqId]) {
            usleep(NUM_1000 * NUM_50);
            bool result = ReadDataTask(requestTask, connection);
            if (result) {
                break;
            }
        }
    };
    std::thread t(recvTask, requestTask, connection);
    t.detach();
}

Connection CreateConnection(RequestTask *requestTask)
{
    struct Connection connection;
    connection.host = requestTask->host;
    connection.path = requestTask->path;
    connection.reqId = requestTask->reqId;
    connection.rpcType = requestTask->rpcType;
    connection.ca = requestTask->ca;
    connection.cert = requestTask->cert;
    connection.key = requestTask->key;
    return connection;
}

void HandleWrite(RequestTask *requestTask)
{
    std::string reqId = requestTask->reqId;
    LOGE("napi-->Write reqId :%s fd %d", reqId.c_str(), requestTask->fd);
    auto connection = CreateConnection(requestTask);
    int rv = HandleSSLShake(&connection, requestTask->fd, requestTask->host);
    if (rv < 0) {
        LOGE("HandleSSLShake Error reqId :%s", reqId.c_str());
        std::string error = "Error handshake failed";
        g_postEvent(HTTP_STREAM_CALLBACK_TYPE_ERROR, const_cast<char *>(error.c_str()), 0, 1, requestTask->reqId);
        return;
    }
    nfds_t npollfds = 1;
    struct pollfd pollfds[1];
    Connection* connectionObj = &connection;
    g_connectManagerMap[reqId] = connectionObj;
    Connection sendDataResult = SendData(connectionObj, requestTask->buff,
        requestTask->buffLen, requestTask->extendParams);
    auto it = g_connectManagerMap.Find(reqId);
    if (it != g_connectManagerMap.End() && it->second) {
        it->second->streamId = sendDataResult.streamId;
        it->second->recvLargeDataFlags = sendDataResult.recvLargeDataFlags;
    }
    pollfds[0].fd = requestTask->fd;
    CtlPoll(pollfds, connection.session, connection.wantIo);
    bool streamError = false;
    if ((connection.rpcType == DUPLEX_STREAM_RPC) && !sendDataResult.dataFlags) {
        ReadDataThread(requestTask, connection);
    }
    while (g_streamCloseManagerMap.Find(requestTask->reqId) == g_streamCloseManagerMap.End()) {
        if (requestTask->fd < 0 || IsDestroyed(requestTask->reqId)) {
            break;
        }
        if (nghttp2_session_want_read(connection.session) || nghttp2_session_want_write(connection.session)) {
            LOGE("the message task enters the reading or writing state reqId %s", requestTask->reqId.c_str());
            bool result = ReadWriteBuffer(pollfds, npollfds, connection, requestTask, streamError);
            if (result) {
                break;
            }
        }
    }
    LOGE("the message task end close reqId %s", requestTask->reqId.c_str());
    if (streamError) {
        std::string error = "-1";
        g_postEvent(HTTP_STREAM_CALLBACK_TYPE_ERROR, const_cast<char *>(error.c_str()), 0, 1, requestTask->reqId);
    }
    if (IsDestroyed(requestTask->reqId)) {
        return;
    }
    FreeResource(&connection);
}

void HandleEnd(Connection *connection)
{
    if (connection->reqId.empty() || !CheckReqId(&connection->reqId)) {
        return;
    }
    if (g_freeManagerMap.Find(connection->reqId) != g_freeManagerMap.End()) {
        LOGE("freeManagerMap find success reqId %s len %d", connection->reqId.c_str(), g_callbackManagerMap.Size());
        g_freeManagerMap.Erase(connection->reqId);
        return;
    }
    g_postEvent(HTTP_CALLBACK_TYPE_CLOSE, const_cast<char *>("0"), 0, connection->rpcType, connection->reqId);
}

void FreeCallBackRef(RequestCallback *requestCallback)
{
    if (!requestCallback) {
        return;
    }
    if ((requestCallback->rpcType == UNARY_STREAM_RPC &&
        requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE_DATA_TRUNCK) ||
        requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE) {
        DeleteCallBackRef(requestCallback->env, requestCallback->reqId);
    }
    FreeRequestCallback(requestCallback);
}

void CallJs(uv_work_t *work)
{
    if (!work) {
        return;
    }
    RequestCallback *requestCallback = (RequestCallback *)(work->data);
    napi_handle_scope scope = nullptr;
    if (!requestCallback || !requestCallback->env) {
        return;
    }
    napi_open_handle_scope(requestCallback->env, &scope);
    if (!requestCallback->callbackRef ||
        g_callbackManagerMap.Find(requestCallback->reqId) == g_callbackManagerMap.End()) {
        FreeRequestCallback(requestCallback);
        delete work;
        return;
    }
    napi_value reqIdNV;
    napi_value typeNV;
    napi_value dataNV;
    napi_value rpcTypeNV;
    napi_create_int32(requestCallback->env, requestCallback->type, &typeNV);
    napi_create_int32(requestCallback->env, requestCallback->rpcType, &rpcTypeNV);
    HandleResponseData(requestCallback, &dataNV);
    napi_value ret = 0;
    napi_value callback = nullptr;
    LOGE("napi-->uv_queue_work reqId %s type %d callback %p", requestCallback->reqId.c_str(), requestCallback->type,
         requestCallback->callbackRef);
    napi_create_string_utf8(requestCallback->env, requestCallback->reqId.c_str(), NAPI_AUTO_LENGTH, &reqIdNV);
    napi_get_reference_value(requestCallback->env, requestCallback->callbackRef, &callback);
    if ((requestCallback->type != HTTP_STREAM_CALLBACK_TYPE_END) && dataNV) {
        napi_value argv_4[] = {reqIdNV, typeNV, dataNV, rpcTypeNV};
        napi_call_function(requestCallback->env, nullptr, callback, NUM_4, argv_4, &ret);
        if (requestCallback->data && (requestCallback->type != HTTP_STREAM_CALLBACK_TYPE_GOWAY)) {
            free(requestCallback->data);
            requestCallback->data = nullptr;
        }
    } else {
        napi_value argv_3[] = {reqIdNV, typeNV, rpcTypeNV};
        napi_call_function(requestCallback->env, nullptr, callback, NUM_3, argv_3, &ret);
    }
    if ((requestCallback->type == HTTP_STREAM_CALLBACK_TYPE_RESPONSE_DATA_TRUNCK) && (requestCallback->rpcType == 1)) {
        g_callJsCheckDataManagerMap[requestCallback->reqId] = true; //回调data完毕
    }
    napi_close_handle_scope(requestCallback->env, scope);
    FreeCallBackRef(requestCallback);
    delete work;
}

void OnEventListener(int type, void *data, int len, int rpcType, std::string requestId)
{
    RequestCallback *requestCallback = HandleRequestCallback(type, data, len, rpcType, requestId);
    if (!requestCallback) {
        LOGE("Error OnEventListener requestCallback null reqId %s", requestId.c_str());
        return;
    }
    uv_loop_s *loopMessage = nullptr;
    auto envManagerIt = g_envManagerMap.Find(requestId);
    if (envManagerIt == g_envManagerMap.End()) {
        LOGE("Error OnEventListener envManagerMap not found reqId %s", requestId.c_str());
        FreeRequestCallback(requestCallback);
        return;
    }
    napi_get_uv_event_loop(envManagerIt->second, &loopMessage);
    if (loopMessage == nullptr) {
        LOGE("Error OnEventListener loopMessage null reqId %s", requestId.c_str());
        FreeRequestCallback(requestCallback);
        return;
    }
    uv_work_t *work = new (std::nothrow) uv_work_t;
    if (work == nullptr) {
        LOGE("Error OnEventListener work null reqId %s", requestId.c_str());
        FreeRequestCallback(requestCallback);
        return;
    }
    work->data = requestCallback;
    LOGE("OnEventListener uv_queue_work type %d reqId %s", requestCallback->type, requestId.c_str());
    uv_queue_work(
        loopMessage, work, [](uv_work_t *work) {},
        [](uv_work_t *work, int status) {
            CallJs(work);
        });
}

RequestTask* HandleRequestParams(napi_env env, napi_callback_info info)
{
    std::string reqId;
    std::string host;
    napi_deferred deferred;
    std::string path;
    std::string extendParams;
    size_t argc = PARAM_COUNT_5;
    napi_value args[PARAM_COUNT_5] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, reqId);
    NapiUtil::JsValueToString(env, args[INDEX_1], STR_DEFAULT_SIZE, host);
    NapiUtil::JsValueToString(env, args[INDEX_2], STR_DEFAULT_SIZE, path);
    NapiUtil::JsValueToString(env, args[INDEX_3], STR_DEFAULT_SIZE, extendParams);
    napi_value callback = args[INDEX_4];
    napi_ref callBackRefMessage;
    napi_create_reference(env, callback, 1, &callBackRefMessage);
    SetEnvMessage(reqId, env);
    SetCallBackRef(reqId, callBackRefMessage);
    MessageCallback(OnEventListener);
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    RequestTask *requestTask = new RequestTask{
        .env = env,
        .asyncWork = nullptr,
        .deferred = deferred,
        .reqId = reqId,
        .host = host,
        .path = path,
        .extendParams = extendParams,
        .promise = promise
    };
    g_requestManagerMap[reqId] = requestTask;
    return requestTask;
}

int ConnectTo(const char *host, uint16_t port)
{
    LOGE("ConnectTo host %s port %d", host, port);
    struct addrinfo hints;
    int fd = -1;
    int rv;
    char service[NI_MAXSERV];
    struct addrinfo *res;
    struct addrinfo *rp;
    rv = snprintf_s(service, sizeof(service), sizeof(service), "%u", port);
    if (rv < 0) {
        LOGE("ConnectTo failed rv %d", rv);
        return -1;
    }
    memset_s(&hints, sizeof(struct addrinfo), 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    rv = getaddrinfo(host, service, &hints, &res);
    if (rv != 0) {
        LOGE("getaddrinfo failed %s", gai_strerror(rv));
        return -1;
    }
    for (rp = res; rp; rp = rp->ai_next) {
        fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (fd == -1) {
            continue;
        }
        while ((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 && errno == EINTR) {
            if (rv < 0) {
                LOGE("connect failed rv %d", rv);
            }
        }
        if (rv == 0) {
            break;
        }
        close(fd);
        fd = -1;
    }
    freeaddrinfo(res);
    return fd;
}

napi_value Http2Napi::ClassConstructor(napi_env env, napi_callback_info info)
{
    LOGE("napi-->ClassConstructor");
    napi_value targetObj = nullptr;
    size_t argc = PARAM_COUNT_0;
    napi_value args[PARAM_COUNT_1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, &targetObj, nullptr);
    Http2Napi *http2Napi = new Http2Napi();
    napi_wrap(
        env, targetObj, http2Napi,
        [](napi_env env, void *data, void *hint) {
            Http2Napi *http2NapiObj = (Http2Napi *)data;
            delete http2NapiObj;
            http2NapiObj = nullptr;
        },
        nullptr, nullptr);
    return targetObj;
}


napi_value Http2Napi::Connect(napi_env env, napi_callback_info info)
{
    LOGE("napi-->Connect");
    size_t argc = PARAM_COUNT_2;
    napi_value args[PARAM_COUNT_2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string host;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, host);
    std::string port;
    NapiUtil::JsValueToString(env, args[INDEX_1], STR_DEFAULT_SIZE, port);
    napi_deferred deferred;
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    napi_value result;
    napi_status napi_status = napi_create_int32(env, 0, &result);
    if ((napi_status == napi_ok) && deferred) {
        napi_resolve_deferred(env, deferred, result);
    }
    return promise;
}

napi_value Http2Napi::Request(napi_env env, napi_callback_info info)
{
    RequestTask *requestTask = HandleRequestParams(env, info);
    LOGE("napi--->Request reqId %s", requestTask->reqId.c_str());
    napi_value result;
    napi_status napi_status = napi_create_string_utf8(env, requestTask->reqId.c_str(), NAPI_AUTO_LENGTH, &result);
    if ((napi_status == napi_ok) && requestTask->deferred && requestTask->env) {
        napi_resolve_deferred(requestTask->env, requestTask->deferred, result);
    }
    return requestTask->promise;
}

void HandleConnectAndSendData(void *data)
{
    if (!data) {
        LOGE("Error HandleConnectAndSendData");
        return;
    }
    RequestTask *requestTask = (RequestTask *)data;
    LOGE("HandleConnectAndSendData reqId %s rpcType %d isDestroy %d", requestTask->reqId.c_str(),
        requestTask->rpcType, IsDestroyed(requestTask->reqId));
    if ((requestTask->rpcType != DUPLEX_STREAM_RPC) || ((requestTask->rpcType == DUPLEX_STREAM_RPC) &&
           (IsDestroyed(requestTask->reqId) ||
               (g_sessionManagerMap.Find(requestTask->reqId) == g_sessionManagerMap.End())))) {
        g_sessionManagerMap[requestTask->reqId] = 0;
        auto domain = ParseDomain(requestTask->host);
        int fd = ConnectTo(domain.host.c_str(), NapiUtil::StringToInt(domain.port.c_str()));
        LOGE("ConnectTo fd %d reqId %s", fd, requestTask->reqId.c_str());
        requestTask->fd = fd;
        if (!requestTask) {
            return;
        }
        HandleWrite(requestTask);
    } else {
        auto connectManagerIt = g_connectManagerMap.Find(requestTask->reqId);
        if (connectManagerIt != g_connectManagerMap.End()) {
            SendDataByStreamId(connectManagerIt->second,
                requestTask->buff, requestTask->buffLen);
        } else {
            LOGE("Error SendDataByStreamId reqId %s", requestTask->reqId.c_str());
        }
    }
}

RequestTask *CreateWriteRequest(void *buffer, size_t bufferLen, RequestTask *requestTask,
    napi_env env, std::string reqId)
{
    if (bufferLen <= 0 || bufferLen > MAX_ALLOC_SIZE) {
        LOGE("CreateWriteRequest Invalid buffer length: %d", bufferLen);
        return nullptr;
    }
    void* bufCopy = malloc(bufferLen);
    if (!bufCopy) {
        return nullptr;
    }
    //拷贝内存副本重新赋值防止出现脏数据，解决问题grpc:received message larger than max
    if (memcpy_s(bufCopy, bufferLen, buffer, bufferLen) != 0) {
        return nullptr;
    }
    RequestTask *requestTaskCopy = new RequestTask{.env = env, .asyncWork = nullptr,
                                                .host = requestTask->host, .path = requestTask->path,
                                                .buff = bufCopy, .reqId = reqId,
                                                .extendParams = requestTask->extendParams,
                                                .ca = requestTask->ca, .cert = requestTask->cert,
                                                .key = requestTask->key, .rpcType = requestTask->rpcType,
                                                .buffLen = static_cast<int>(bufferLen)};
    return requestTaskCopy;
}

void HandleRpcType(RequestTask *requestTask, string rpcType, string reqId)
{
    if (!rpcType.empty()) {
        int rpcTypeInt = NapiUtil::StringToInt(rpcType);
        if (rpcTypeInt == UNARY_STREAM_RPC || rpcTypeInt == WRITABLE_STREAM_RPC ||
            rpcTypeInt == READABLE_STREAM_RPC || rpcTypeInt == DUPLEX_STREAM_RPC) {
            requestTask->rpcType = NapiUtil::StringToInt(rpcType);
            g_requestManagerMap[reqId] = requestTask;
        }
    }
}

bool HandleCertAndCheckHost(RequestTask *requestTask, string cert, string key, string ca)
{
    if (!cert.empty() && !key.empty()) {
        requestTask->ca = ca;
        requestTask->cert = cert;
        requestTask->key = key;
    }
    if (requestTask->host.size() <= 0 || requestTask->host.size() > NUM_1000) {
        return false;
    }
    return true;
}

napi_value Http2Napi::Write(napi_env env, napi_callback_info info)
{
    size_t argc = PARAM_COUNT_6;
    napi_value args[PARAM_COUNT_6] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string reqId;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, reqId);
    void *buffer;
    size_t bufferLen;
    napi_get_arraybuffer_info(env, args[INDEX_1], &buffer, &bufferLen);
    std::string rpcType;
    NapiUtil::JsValueToString(env, args[INDEX_2], STR_DEFAULT_SIZE, rpcType);
    std::string ca;
    NapiUtil::JsValueToString(env, args[INDEX_3], STR_DEFAULT_SIZE, ca);
    std::string cert;
    NapiUtil::JsValueToString(env, args[INDEX_4], STR_DEFAULT_SIZE, cert);
    std::string key;
    NapiUtil::JsValueToString(env, args[INDEX_5], STR_DEFAULT_SIZE, key);
    LOGE("Napi--->Write reqId %s rpcType %s ca %s cert %s key %s", reqId.c_str(),
        rpcType.c_str(), ca.c_str(), cert.c_str(), key.c_str());
    auto requestManagerIt = g_requestManagerMap.Find(reqId);
    if (requestManagerIt == g_requestManagerMap.End()) {
        return nullptr;
    }
    RequestTask *requestTask = requestManagerIt->second;
    HandleRpcType(requestTask, rpcType, reqId);
    HandleCertAndCheckHost(requestTask, cert, key, ca);
    if (!HandleCertAndCheckHost(requestTask, cert, key, ca)) {
        return nullptr;
    }
    auto requestTaskCopy = CreateWriteRequest(buffer, bufferLen, requestTask,
        env, reqId);
    if (!requestTaskCopy) {
        return nullptr;
    }
    if (requestTask->rpcType == READABLE_STREAM_RPC) {
        auto reqTask = [](void *data) { HandleConnectAndSendData(data); };
        std::thread t(reqTask, requestTaskCopy);
        t.detach();
    } else {
        napi_value resourceName;
        napi_create_string_latin1(env, "write", NAPI_AUTO_LENGTH, &resourceName);
        napi_create_async_work(
            env, nullptr, resourceName, [](napi_env env, void *data) { HandleConnectAndSendData(data); },
            [](napi_env env, napi_status status, void *data) { EndWriteTask(env, data); }, requestTaskCopy,
            &requestTaskCopy->asyncWork);
        napi_queue_async_work(env, requestTaskCopy->asyncWork);
    }
    return nullptr;
}

napi_value Http2Napi::End(napi_env env, napi_callback_info info)
{
    size_t argc = PARAM_COUNT_2;
    napi_value args[PARAM_COUNT_2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string reqId;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, reqId);
    LOGE("napi--->End reqId %s", reqId.c_str());
    auto freeManagerIt = g_freeManagerMap.Find(reqId);
    if (freeManagerIt != g_freeManagerMap.End() && freeManagerIt->second) {
        g_sessionManagerMap[reqId] = 1;
        g_freeManagerMap.Erase(reqId);
        g_postEvent(HTTP_CALLBACK_TYPE_CLOSE, const_cast<char *>("0"),
            0, NUM_1, reqId);
        return nullptr;
    }
    auto resIt = g_connectManagerMap.Find(reqId);
    if (resIt != g_connectManagerMap.End()) {
        if (g_sessionManagerMap.Find(reqId) == g_sessionManagerMap.End()) {
            return nullptr;
        }
        g_sessionManagerMap[reqId] = 1;
        napi_deferred deferred;
        napi_value promise;
        napi_create_promise(env, &deferred, &promise);
        Connection *connection = resIt->second;
        if (!connection || !CheckReqId(&connection->reqId)) {
            g_postEvent(HTTP_CALLBACK_TYPE_CLOSE, const_cast<char *>("0"), 0, NUM_1, reqId);
            return nullptr;
        }
        Connection *connectionTemp = new Connection{.ssl = connection->ssl, .fd = connection->fd, .reqId = reqId,
                                                 .sslCtx = connection->sslCtx, .env = env, .deferred = deferred,
                                                 .session = connection->session};
        g_sessionManagerMap[reqId] = true;
        HandleEnd(connectionTemp);
        auto endTask = [](Connection *connection) {
            LOGE("napi--->End success reqId %s", connection->reqId.c_str());
            usleep(NUM_1000 * NUM_100);
            FreeResource(connection);
        };
        std::thread t(endTask, connectionTemp);
        t.detach();
        EndStreamTask(env, connectionTemp);
        return promise;
    } else {
        LOGE("Error End reqId %s", reqId.c_str());
    }
    return nullptr;
}

napi_value Http2Napi::DnsResolveTxt(napi_env env, napi_callback_info info)
{
    LOGE("napi-->DnsResolveTxt");
    size_t argc = PARAM_COUNT_1;
    napi_value args[PARAM_COUNT_1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string host;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, host);
    napi_deferred deferred;
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    napi_value result;
    napi_status napi_status = napi_create_string_utf8(env, host.c_str(), NAPI_AUTO_LENGTH, &result);
    if ((napi_status == napi_ok) && deferred) {
        napi_resolve_deferred(env, deferred, result);
    }
    LOGE("napi-->DnsResolveTxt success");
    return promise;
}

napi_value Http2Napi::DnsLookup(napi_env env, napi_callback_info info)
{
    LOGE("napi-->DnsLookup");
    size_t argc = PARAM_COUNT_1;
    napi_value args[PARAM_COUNT_1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    std::string host;
    NapiUtil::JsValueToString(env, args[INDEX_0], STR_DEFAULT_SIZE, host);
    napi_deferred deferred;
    napi_value promise;
    napi_create_promise(env, &deferred, &promise);
    napi_value result;
    napi_status napi_status = napi_create_string_utf8(env, host.c_str(), NAPI_AUTO_LENGTH, &result);
    if ((napi_status == napi_ok) && deferred) {
        napi_resolve_deferred(env, deferred, result);
    }
    LOGE("napi-->DnsLookup success");
    return promise;
}

napi_value Http2Napi::OpenNativeLog(napi_env env, napi_callback_info info)
{
    g_ohosLogOn = true;
    return nullptr;
}